package cn.itsource.ymcc.service.impl;

import cn.itsource.ymcc.domain.Login;
import cn.itsource.ymcc.dto.LoginDto;
import cn.itsource.ymcc.jwt.JwtUtils;
import cn.itsource.ymcc.jwt.PayloadData;
import cn.itsource.ymcc.jwt.RsaUtils;
import cn.itsource.ymcc.mapper.LoginMapper;
import cn.itsource.ymcc.service.ILoginService;
import cn.itsource.ymcc.util.AssertUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 登录表 服务实现类
 * </p>
 *
 * @author whale.chen
 * @since 2024-06-06
 */
@Service
public class LoginServiceImpl extends ServiceImpl<LoginMapper, Login> implements ILoginService {

    /**
     * 统一认证接口（登录）
     * @param loginDto
     * @return
     */
    @Override
    public Map<String, String> accountLogin(LoginDto loginDto) {
        //1.参数校验
        //2.通过用户名查询数据  select * from t_login where username = ? and type = ?
        Login login = baseMapper.selectOne(new QueryWrapper<Login>()
                .eq("username", loginDto.getUsername())
                .eq("type", loginDto.getType()));

        //构建查询条件
//        LambdaQueryWrapper<Login> wrapper = new LambdaQueryWrapper<>();
//        wrapper.eq(Login::getUsername,username);// eq等于查询
//        QueryWrapper<Login> wrapper1 = new QueryWrapper<>();
//        wrapper1.eq("username",username);
        //执行sql
        //select * from t_login where username = ? and type = ?
        /*Login login = super.getOne(new LambdaQueryWrapper<Login>()
                .eq(Login::getUsername,loginDto.getUsername())
                .eq(Login::getType,loginDto.getType()));*/

        //断言工具类：判断第一个参数对象非空，否则就抛出异常，异常消息是第二个参数
        AssertUtil.isNotNull(login, "用户名错误！");

        //比较密码 PasswordEncoder是SpringSecurity的工具类
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        boolean matches = passwordEncoder.matches(loginDto.getPassword(), login.getPassword());
        AssertUtil.isTrue(matches, "密码错误！");

        /**
         * 密码匹配成功：登录成功
         *  1.基于Redis
         *      用户类型为0的时候（后台管理系统用户），连表查询当前登录用户拥有的权限和菜单
         *      生成一个UUID作为key，将Login对象作为值，存储到Redis中
         *      封装一个HashMap返回前端
         *  2.基于JWT
         *      用户类型为0的时候（后台管理系统用户），连表查询当前登录用户拥有的权限和菜单
         *      JWT工具类生成JWT字符串
         *      封装一个HashMap返回前端
         */
        return loginSuccess(login);
    }

    /**
     * 专门处理登录成功的业务
     * @param login
     * @return
     */
    private Map<String, String> loginSuccess(Login login) {
        Map<String, String> map = new HashMap<>();
        try {
            //1.用户类型为0的时候（后台管理系统用户），连表查询当前登录用户拥有的权限和菜单  [今天先不做]
            //2.JWT工具类生成JWT字符串  私钥加密  公钥解密
            PrivateKey privateKey = RsaUtils
                    .getPrivateKey(FileCopyUtils
                            .copyToByteArray(this.getClass().getClassLoader().getResourceAsStream("hrm_auth_rsa")));
            //加密得到token
            PayloadData payloadData = new PayloadData();
            login.setPassword(null);    //置空密码，更安全
            payloadData.setLogin(login);
            String token = JwtUtils.generateTokenExpireInMinutes(payloadData, privateKey, 60*24);  //24小时过期

            //3.封装到HashMap
            map.put("token", token);
            map.put("currentUser", JSON.toJSONString(login));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return map;
    }
}
